package com.grandtech.insurance.common.db.mongdb;



import com.grandtech.insurance.common.bean.SqlVo;
import com.grandtech.insurance.common.compress.ObjZip;
import com.grandtech.insurance.common.core.bean.Tile;
import com.grandtech.insurance.common.core.bean.TileSchemeCore;
import com.grandtech.insurance.common.core.coding.Feature;
import com.grandtech.insurance.common.core.coding.VectorTileEncoder;
import com.grandtech.insurance.common.core.dao.ITileDao;
import com.grandtech.insurance.common.core.spatial.SpatialTree;
import com.grandtech.insurance.common.core.utils.TileUtil;
import com.grandtech.insurance.common.core.utils.TileUtils;
import com.grandtech.insurance.common.db.mongdb.dao.IMongoDao;
import com.grandtech.insurance.common.db.mongdb.dao.IMongoDao1;
import com.grandtech.insurance.common.utils.SpringBeanUtil2;
import com.mapbox.geojson.BoundingBox;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.WKBReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.mongodb.core.MongoTemplate;

import java.util.List;
import java.util.Map;

/**
 * 局部,同步切片  (minZ级别数据缓存起来)
 */
public final class TileTaskSync {

    Log log = LogFactory.getLog(TileTaskSync.class);

    /**
     * Feature索引树
     */
    SpatialTree spatialTree;

    //pg和mongo操作类
    TileSchemeCore tileSchemeCore;
    MongoTemplate mongoTemplate;
    ITileDao iTileDao;
    IMongoDao<Tile> iMongoDao;

    //切片参数
    private String mongoTileName;
    private String layerName;
    private String sqlTemplate;
    private String beforeTileSql;
    private String sql;
    private String shapeField;
    private String sqlTile;
    private int extent;
    private int buffer;
    private boolean autoScale;

    //切片对象
    List<Map> featureList;
    VectorTileEncoder vte;
    Geometry shape;
    Map<String, Object> attribute;
    WKBReader wkbReader;
    byte[] data;
    Tile tile;

    //切片范围
    long minZ, maxZ;
    Map<String, List<long[]>> treeTiles;
    Feature feature;
    Envelope envelope;
    List<Feature> features;

    ObjZip objZip;

    public TileTaskSync(TileSchemeCore tileSchemeCore, List<BoundingBox> bounds) {
        this.tileSchemeCore = tileSchemeCore;

        this.iTileDao = SpringBeanUtil2.getBean(ITileDao.class);
        this.iMongoDao = SpringBeanUtil2.getBean(IMongoDao.class);

        this.tileSchemeCore = tileSchemeCore;
        this.mongoTemplate = tileSchemeCore.getMongoTemplate();
        this.iMongoDao.setMongoTemplate(tileSchemeCore.getMongoTemplate());
        this.layerName = tileSchemeCore.getTileId();
        this.mongoTileName = tileSchemeCore.getMongoTileName();
        this.sqlTemplate = tileSchemeCore.getSqlTemplate();
        this.beforeTileSql = tileSchemeCore.getBeforeTile();
        this.shapeField = tileSchemeCore.getShapeField();
        this.extent = tileSchemeCore.getExtent();
        this.buffer = tileSchemeCore.getClipBuffer();
        this.autoScale = tileSchemeCore.getAutoScale();

        this.wkbReader = new WKBReader();
        this.vte = new VectorTileEncoder(extent, buffer, autoScale);

        this.minZ = tileSchemeCore.getMinZoom();
        this.maxZ = tileSchemeCore.getMaxZoom();
        this.treeTiles = TileUtil.getTreeBoundTile(bounds, minZ, maxZ);
        this.objZip = new ObjZip();
    }

    public void startTile() {
        long t1 = System.currentTimeMillis();
        if (beforeTileSql != null && !beforeTileSql.trim().equals(""))
            iTileDao.exeSql(new SqlVo(beforeTileSql));
        StringBuilder info = new StringBuilder();
        List<long[]> tileMinZ;
        long[] tileL;
        Tile tile;
        try {
            for (String tileMinId : treeTiles.keySet()) {
                tileMinZ = treeTiles.get(tileMinId);
                if (tileMinZ == null) continue;
                spatialTree = new SpatialTree();
                for (int i = 0, len = tileMinZ.size(); i < len; i++) {
                    tileL = tileMinZ.get(i);
                    info.setLength(0);
                    info.append(tileL[0]).append("|").append(tileL[1]).append("|").append(tileL[2]);
                    log.info(info);
                    if (tileL[0] == minZ) {
                        tile = tileFromDb(tileL[0], tileL[1], tileL[2]);
                    } else {
                        tile = tileFromCache(tileL[0], tileL[1], tileL[2]);
                    }
                    iMongoDao.deleteTile(mongoTileName, tileL[0], tileL[1], tileL[2]);
                    if (!tile.hasData()) continue;
                    iMongoDao.insert(tile, mongoTileName);
                }
                spatialTree = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            long t2 = System.currentTimeMillis();
            log.info("切片耗时:" + (t2 - t1) + "[ms]");
        }
    }

    public Tile tileFromDb(long z, long x, long y) throws Exception {
        vte.clear();
        sqlTile = TileUtil.parseXyz2Bound(x, y, z);
        sql = sqlTemplate.replace("?", sqlTile);
        featureList = iTileDao.queryFeatures(new SqlVo(sql));
        for (int i = 0, len = featureList.size(); i < len; i++) {
            attribute = featureList.get(i);
            byte[] bytes = WKBReader.hexToBytes(attribute.get(shapeField).toString());
            shape = wkbReader.read(bytes);
            attribute.remove(shapeField);
            feature = new Feature(layerName, (Geometry) shape.clone(), attribute);
            spatialTree.insert(feature);
            TileUtil.convert2Pixel(x, y, z, shape);
            vte.addFeature(feature.getLayerName(), feature.getAttributes(), shape);
        }
        data = vte.encode();
        data = objZip.gZip(data);
        tile = new Tile(z, x, y, data);
        return tile;
    }

    /**
     * 次低级别从内存里切
     *
     * @param z
     * @param x
     * @param y
     * @return
     * @throws Exception
     */
    public Tile tileFromCache(long z, long x, long y) throws Exception {
        vte.clear();
        envelope = TileUtil.xyz2Envelope(x, y, z);
        features = spatialTree.query(envelope);
        for (int i = 0, len = features.size(); i < len; i++) {
            feature = features.get(i);
            shape = (Geometry) feature.getGeometry().clone();
            TileUtil.convert2Pixel(x, y, z, shape);
            vte.addFeature(feature.getLayerName(), feature.getAttributes(), shape);
        }
        data = vte.encode();
        data = objZip.gZip(data);
        tile = new Tile(z, x, y, data);
        return tile;
    }



}
